package com.shanjupay.transaction.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shanjupay.common.cache.Cache;
import com.shanjupay.common.domain.BusinessException;
import com.shanjupay.common.domain.CommonErrorCode;
import com.shanjupay.common.util.RedisUtil;
import com.shanjupay.transaction.api.PayChannelService;
import com.shanjupay.transaction.api.dto.PayChannelDTO;
import com.shanjupay.transaction.api.dto.PayChannelParamDTO;
import com.shanjupay.transaction.api.dto.PlatformChannelDTO;
import com.shanjupay.transaction.convert.PayChannelParamConvert;
import com.shanjupay.transaction.convert.PlatformChannelConvert;
import com.shanjupay.transaction.entity.AppPlatformChannel;
import com.shanjupay.transaction.entity.PayChannelParam;
import com.shanjupay.transaction.entity.PlatformChannel;
import com.shanjupay.transaction.mapper.AppPlatformChannelMapper;
import com.shanjupay.transaction.mapper.PayChannelParamMapper;
import com.shanjupay.transaction.mapper.PlatformChannelMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Transactional
@Slf4j
@Service
public class PayChannelServiceImpl  implements PayChannelService {

    @Autowired
    private PlatformChannelMapper platformChannelMapper;

    @Autowired
    private AppPlatformChannelMapper appPlatformChannelMapper;

    @Autowired
    private PayChannelParamMapper payChannelParamMapper;

    @Autowired
    private Cache cache ;


    /**
     * 获取指定应用指定服务类型下所包含的某个原始支付参数
     *
     * @param appId
     * @param platformChannel
     * @param payChannel
     * @return
     * @throws BusinessException
     */
    @Override
    public PayChannelParamDTO queryParamByAppPlatformAndPayChannel(String appId, String platformChannel, String payChannel) throws BusinessException {
        List<PayChannelParamDTO> payChannelParamDTOS = queryPayChannelParamByAppAndPlatform(appId, platformChannel);
        for (PayChannelParamDTO paramDTO : payChannelParamDTOS){
            if (paramDTO.getPayChannel().equals(payChannel)){
                return paramDTO;
            }
        }
        return null;
    }

    /**
     * 获取指定应用指定服务类型下所包含的原始支付渠道参数列表。
     *
     * @param appId           应用id
     * @param platformChannel 服务类型
     * @return
     * @throws BusinessException
     */
    @Override
    public List<PayChannelParamDTO> queryPayChannelParamByAppAndPlatform(String appId, String platformChannel) throws BusinessException {

        // 先从redis 查询，如果有则返回
        String redisKey = RedisUtil.keyBuilder(appId,platformChannel);
        Boolean exists = cache.exists(redisKey);
        if(exists){
            // 从redis 获取支付渠道参数列表
            String result = cache.get(redisKey);
            // 将json 串 转成列表返回
            List<PayChannelParamDTO> payChannelParamDTOS = JSON.parseArray(result, PayChannelParamDTO.class);
            return payChannelParamDTOS;
        }

        // 根据应用和服务类型找到他们绑定的id
        Long appPlatformChannelId = selectIdByAppPlatformChannel(appId, platformChannel);
        if(appPlatformChannelId == null ){
            return  null ;
        }
        // 应用和服务类型绑定id 查询支付渠道参数记录
        List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(new LambdaQueryWrapper<PayChannelParam>()
                .eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId));

        List<PayChannelParamDTO> payChannelParamDTOS = PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParams);

        // 保存redis
        updateCache(appId,platformChannel);

        return payChannelParamDTOS;
    }

    /**
     * 根据应用和服务类型将查询到支付渠道参数配置 列表写入redis
     *
     * @param appId  应用id
     * @param platformChannelCode 服务类型Code
     */
    private void updateCache(String appId, String platformChannelCode) {
        // 得到redis 中key （支付渠道参数配置列表的key)
        // 格式： SJ_PAY_PARAM:应用id:服务类型code
        String redisKey = RedisUtil.keyBuilder(appId,platformChannelCode);
        // 根据key查询redis
        Boolean exists = cache.exists(redisKey);
        if(exists){
            cache.del(redisKey);
        }

        // 根据应用id 和 服务类型code 查询支付渠道参数列表， 将写入支付渠道参数列表 写入redis

        Long appPlatformChannelId = selectIdByAppPlatformChannel(appId, platformChannelCode);
        if(appPlatformChannelId != null){
            // 应用和服务类型绑定id 查询支付渠道参数记录
            List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(new LambdaQueryWrapper<PayChannelParam>()
                    .eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId));

            List<PayChannelParamDTO> payChannelParamDTOS = PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParams);
            // 将 list 转成json 串 存入redis
            cache.set(redisKey, JSON.toJSON(payChannelParamDTOS).toString());
        }


        //List<PayChannelParamDTO> payChannelParamDTOS = queryPayChannelParamByAppAndPlatform(appId, platformChannelCode);
        // 将支付渠道参数列表存储到redis
        //if(payChannelParamDTOS != null ){
            // 将 list 转成json 串 存入redis
            //cache.set(redisKey, JSON.toJSON(payChannelParamDTOS).toString());
        //}

    }

    /**
     * 获取平台服务类型
     *
     * @return
     * @throws BusinessException
     */
    @Override
    public List<PlatformChannelDTO> queryPlatformChannel() throws BusinessException {
        List<PlatformChannel> platformChannels = platformChannelMapper.selectList(null);
        List<PlatformChannelDTO> platformChannelDTOS = PlatformChannelConvert.INSTANCE.listentity2listdto(platformChannels);
        return platformChannelDTOS;
    }

    /**
     * 为app 绑定平台服务类型
     *
     * @param appId                appId 应用id
     * @param platformChannelCodes 平台服务类型列表
     * @throws BusinessException
     */
    @Override
    public void bindPlatformChannelForApp(String appId, String platformChannelCodes) throws BusinessException {

        // 根据应用id和服务类型code 查询， 如果已经绑定则不再插入，否则插入记录
        AppPlatformChannel platformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>().eq(AppPlatformChannel::getAppId, appId).eq(AppPlatformChannel::getPlatformChannel, platformChannelCodes));

        if(platformChannel == null ){
            // 插入数据
            AppPlatformChannel entity = new AppPlatformChannel();
            // 应用id
            entity.setAppId(appId);
            // 服务类型的code
            entity.setPlatformChannel(platformChannelCodes);
            int insert = appPlatformChannelMapper.insert(entity);
            log.info("插入的结果为：" + insert);
        }
    }

    /**
     * 根据服务类型查询支付渠道
     *
     * @param platformChannelCode
     * @return
     */
    @Override
    public List<PayChannelDTO> queryPayChannelByPlatformChannel(String platformChannelCode) throws BusinessException {

        List<PayChannelDTO> payChannelDTOS = platformChannelMapper.selectPayChannelByPlatformChannel(platformChannelCode);

        return payChannelDTOS;
    }

    /**
     * 应用是否绑定了某个服务类型
     *
     * @param appId
     * @param platformChannel
     * @return 已绑定返回1 ， 否则 返回0
     * @throws BusinessException
     */
    @Override
    public int queryAppBindPlatformChannel(String appId, String platformChannel) throws BusinessException {
        // 根据应用id和服务类型code 查询， 如果已经绑定则不再插入，否则插入记录
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>().eq(AppPlatformChannel::getAppId, appId).eq(AppPlatformChannel::getPlatformChannel, platformChannel));

        if(appPlatformChannel != null ){
            return 1;
        }
        return 0 ;
    }

    /**
     * 保存支付渠道参数
     *
     * @param payChannelParamDTO  配置支付渠道参数： 包括：商户id,` 应用id, 服务类型code, 支付渠道code,
     * @throws BusinessException
     */
    @Override
    public void savePayChannelParam(PayChannelParamDTO payChannelParamDTO) throws BusinessException {
        if(payChannelParamDTO == null || payChannelParamDTO.getChannelName() == null){
            throw new BusinessException(CommonErrorCode.E_300009);
        }
        // 根据应用， 服务类型， 支付渠道， 查询一条记录

        // 根据应用， 服务类型查询应用与服务类型的绑定id
        Long channel = selectIdByAppPlatformChannel(payChannelParamDTO.getAppId(), payChannelParamDTO.getPlatformChannelCode());
        if(channel == null ){
            throw new BusinessException(CommonErrorCode.E_300010);
        }
        // 根据应用与服务类型的绑定id和支付渠道查询PayChannelParam 的一条记录
        PayChannelParam channelParam = payChannelParamMapper.selectOne(new LambdaQueryWrapper<PayChannelParam>().eq(PayChannelParam::getAppPlatformChannelId, channel)
                .eq(PayChannelParam::getPayChannel, payChannelParamDTO.getPayChannel()));
        // 如果存在配置则更新
        if(channelParam != null) {
            // 配置名称
            channelParam.setChannelName(payChannelParamDTO.getChannelName());
            // json 格式的参数
            channelParam.setParam(payChannelParamDTO.getParam());

            int i = payChannelParamMapper.updateById(channelParam);
            log.info("更新结果为：{}",i);
        }else {
            // 否则添加配置
            PayChannelParam payChannelParam = PayChannelParamConvert.INSTANCE.dto2entity(payChannelParamDTO);
            payChannelParam.setId(null);
            // 应用与服务类型绑定关系的Id
            payChannelParam.setAppPlatformChannelId(channel);
            int result = payChannelParamMapper.insert(payChannelParam);
            log.info("更新结果为：{}",result);
        }

        // 保存到redis 中
        updateCache(payChannelParamDTO.getAppId(),payChannelParamDTO.getPlatformChannelCode());
    }

    /**
     * 根据应用， 服务类型查询应用与服务类型的绑定id
     * @param appId
     * @param platformChannelCode
     * @return
     */
    private Long selectIdByAppPlatformChannel(String appId,String platformChannelCode){
        AppPlatformChannel platformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>()
                .eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCode));
        if(platformChannel != null ){
            // 应用与服务类型的绑定id
            return platformChannel.getId();
        }
        return null;
    }

}
